package com.csust.cg.mongodb.service.impl;

import com.csust.cg.mongodb.domain.Result;
import com.csust.cg.mongodb.domain.vo.ConnectionVO;
import com.csust.cg.mongodb.exception.ConnectionException;
import com.csust.cg.mongodb.service.ConnectService;
import com.csust.cg.mongodb.service.RecentConnectService;
import com.csust.cg.mongodb.utils.MongoUtils;
import com.mongodb.client.MongoClient;
import com.mongodb.connection.ClusterType;
import org.apache.commons.lang3.StringUtils;
import org.bson.BsonDocument;
import org.bson.BsonInt64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.StreamSupport;

/**
 * @author chenguang
 */
@Service
public class ConnectServiceImpl implements ConnectService {

    @Autowired
    private RecentConnectService recentConnectService;

    @Override
    public Result connect(ConnectionVO connection, String userId) {
        String connectionId;
        try {
            connectionId = MongoUtils.getConnectionId(connection);
        } catch (ConnectionException e) {
            return new Result(e.getMessage(), e.getCode());
        }
        if (StringUtils.isNotBlank(userId)) {
            // 已登陆，添加最近连接记录
            recentConnectService.addRecentConnect(connection, userId);
        }
        Map<String, Object> result = new HashMap<>(2);
        result.put("connectionId", connectionId);
        result.put("connection", connection);
        return Result.success(null, result);
    }

    @Override
    public Result disConnect(String connectionId) {
        MongoUtils.removeConnectionId(connectionId);
        return Result.success();
    }

    @Override
    public Result getConnectInfo(String connectionId) {
        MongoClient client = MongoUtils.getClient(connectionId);
        ConnectionVO connection = MongoUtils.getConnection(connectionId);
        // 返回结果集
        Map<String, Object> result = new HashMap<>();
        // host
        String host = String.valueOf(client.getClusterDescription().getClusterSettings().getHosts().get(0));
        // version
        String version = client.getDatabase("admin").runCommand(new BsonDocument("buildInfo", new BsonInt64(1))).getString("version");
        // cluster
        ClusterType clusterType = client.getClusterDescription().getType();
        // databaseCount
        long databaseCount = StreamSupport.stream(client.listDatabases().spliterator(), false).count();
        // collectionCount
        AtomicLong collectionCount = new AtomicLong();
        client.listDatabaseNames().forEach(database -> {
            collectionCount.addAndGet(StreamSupport.stream(client.getDatabase(database).listCollectionNames().spliterator(), false).count());
        });
        long collections = collectionCount.get();
        // uri
        StringBuilder uri = new StringBuilder();
        uri.append(connection.getProtocol()).append("://");
        if (connection.getAuth()) {
            uri.append(connection.getUsername()).append(":").append(connection.getPassword()).append("@")
                    .append(connection.getIp()).append(":").append(connection.getPort()).append("/?authMechanism=")
                    .append(connection.getAuthMechanism()).append("&authSource=").append(connection.getAuthDatabase());
        } else {
            uri.append(connection.getIp()).append(":").append(connection.getPort()).append("/");
        }
        // name
        result.put("name", connection.getName());
        // id
        result.put("id", connection.getId());
        // groupId
        if (connection.getGroups() != null && connection.getGroups().size() >= 1) {
            result.put("groupId", connection.getGroups().get(0));
        }
        result.put("uri", uri);
        result.put("Host", host);
        result.put("Edition", version);
        result.put("Cluster", clusterType);
        result.put("databaseCount", databaseCount);
        result.put("collectionCount", collections - 2);
        MongoUtils.closeClient(client);
        return Result.success(result);
    }
}
